﻿using Microsoft.Extensions.Configuration;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Syspetro.Core;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Syspetro.DepMongoDb
{
    public class MongoDbHelper<T> where T : class, new()
    {
        static MongoClient client;
        readonly IMongoDatabase database;
        readonly MongoDbOptions dbOptions;
        public IMongoCollection<T> collection;
        public MongoDbHelper()
        {
            dbOptions = new MongoDbOptions();
            InternalApp.Configuration.Bind("MongoDbOptions", dbOptions);
            if (client == null)
            {
                if (string.IsNullOrEmpty(dbOptions.Username) && string.IsNullOrEmpty(dbOptions.Password))
                {
                    client = new MongoClient($"mongodb://{dbOptions.IP}:{dbOptions.Port}");
                }
                else
                {
                    client = new MongoClient($"mongodb://{dbOptions.Username}:{dbOptions.Password}@{dbOptions.IP}:{dbOptions.Port}");
                }
            }
            database = client.GetDatabase(dbOptions.DbName);
            Type type = typeof(T);
            collection = database.GetCollection<T>(type.Name.ToLower());

            //var db = client.GetDatabase("products");
            //db.GetCollection<T>(type.Name.ToLower()).Indexes
            //var server = client.GetServer();
            //MongoDatabase db = server.GetDatabase("qimenlogs");
            //MongoCollection cc = db.GetCollection("cheshi");
            //cc.CreateIndex("PrimaryAccount");
            //collection.CreateIndex(IndexKeys<collection>.Descending("name"));
            //database.
            //collection.Indexes
        }

        public void DropDatabase(string name = null)
        {
            client.DropDatabase(name ?? dbOptions.DbName);
        }
        public IMongoCollection<U> GetCollection<U>()
        {
            Type type = typeof(U);
            return database.GetCollection<U>(type.Name.ToLower());
        }
        public void InsertOne(T model)
        {
            collection.InsertOne(model);
        }
        public Task InsertOneAsync(T model)
        {
            return collection.InsertOneAsync(model);
        }
        public void InsertMany(params T[] modes)
        {
            collection.InsertMany(modes);
        }
        public Task InsertManyAsync(params T[] modes)
        {
            return collection.InsertManyAsync(modes);
        }
        public IMongoQueryable<T> Select()
        {
            return collection.AsQueryable();
        }
        public IMongoQueryable<T> Select(int pageIndex, int pageSize)
        {
            return collection.AsQueryable().Skip(pageSize * (pageIndex - 1)).Take(pageSize);
        }
        public IMongoQueryable<T> Select(Expression<Func<T, bool>> where, Expression<Func<T, object>> orderBy, int pageIndex, int pageSize, bool IsAscending = false)
        {
            if (orderBy != null)
            {
                if (IsAscending)
                    return collection.AsQueryable().Where(where).OrderBy(orderBy).Skip(pageSize * (pageIndex - 1)).Take(pageSize);
                else
                    return collection.AsQueryable().Where(where).OrderByDescending(orderBy).Skip(pageSize * (pageIndex - 1)).Take(pageSize);
            }
            return collection.AsQueryable().Where(where).Skip(pageSize * (pageIndex - 1)).Take(pageSize);
        }
        public void UpdateMany(Expression<Func<T, bool>> filter, UpdateDefinition<T> update)
        {
            collection.UpdateMany(filter, update);
        }
        public Task UpdateManyAsync(Expression<Func<T, bool>> filter, UpdateDefinition<T> update)
        {
            return collection.UpdateManyAsync(filter, update);
        }
        public void UpdateOne(Expression<Func<T, bool>> filter, T update)
        {
            collection.ReplaceOne(filter, update);
        }
        public Task UpdateOneAsync(Expression<Func<T, bool>> filter, T update)
        {
            return collection.ReplaceOneAsync(filter, update);
        }
        public void DeleteMany(Expression<Func<T, bool>> filter)
        {
            collection.DeleteMany(filter);
        }
        public Task DeleteManyAsync(Expression<Func<T, bool>> filter)
        {
            return collection.DeleteManyAsync(filter);
        }
    }
}
